package net.flyinggroup.scs.gitter.service.impl;

import lombok.extern.slf4j.Slf4j;
import net.flyinggroup.scs.gitter.repository.impl.DefaultUserRepository;
import net.flyinggroup.scs.gitter.service.ChatService;
import net.flyinggroup.scs.gitter.service.gitter.GitterProperties;
import net.flyinggroup.scs.gitter.service.gitter.GitterUriBuilder;
import net.flyinggroup.scs.gitter.service.gitter.dto.MessageResponse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.Arrays;
import java.util.function.Supplier;

@SpringBootApplication(exclude = {MongoReactiveAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class})
@EnableConfigurationProperties(GitterProperties.class)
@Slf4j
@ComponentScan(
        basePackageClasses = GitterService.class,
        excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
                @ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DefaultStatisticService.class)})
public class GitterService implements ChatService<MessageResponse> {
    private final WebClient webClient;
    private final GitterProperties gitterProperties;

    public GitterService(WebClient.Builder builder, GitterProperties properties) {
        this.webClient = builder.defaultHeader("Authorization", "Bearer " + properties.getAuth().getToken()).build();
        this.gitterProperties = properties;
    }

    @Override
    public Flux<MessageResponse> getStreamMessages() {
        return webClient.get()
                .uri(GitterUriBuilder.from(gitterProperties.getStream()).build().toUri())
                .retrieve()
                .bodyToFlux(MessageResponse.class)
                .doOnError(t -> log.error(t.getMessage(), t))
                .retryWhen(Retry.backoff(Long.MAX_VALUE, Duration.ofMillis(5000)))
                .doOnNext(response -> {
                    log.info(response.toString());
                });
    }

    @Override
    public Flux<MessageResponse> getLatestMessages() {
        return webClient.get()
                .uri(GitterUriBuilder.from(gitterProperties.getApi()).build().toUri())
                .retrieve()
                .bodyToFlux(MessageResponse.class)
                .timeout(Duration.ofSeconds(1))
                .retryWhen(Retry.backoff(Long.MAX_VALUE, Duration.ofMillis(500)));
    }

    @Bean
    public Supplier<Flux<MessageResponse>> message() {
        return () -> Flux.concat(this.getLatestMessages(), this.getStreamMessages());
    }

    public static void main(String[] args) {
        String[] newArgs = Arrays.copyOf(args, args.length + 1);
        newArgs[args.length] = "--spring.profiles.active=gitter";

        SpringApplication.run(GitterService.class, newArgs);
    }
}